package com.huifai.controller;


import com.alibaba.fastjson.JSONObject;
import com.huifai.common.ParameterValidator;
import com.huifai.common.cache.RedisService;
import com.huifai.common.constant.ERespCode;
import com.huifai.common.constant.SysConstant;
import com.huifai.common.exception.BadRequestException;
import com.huifai.common.exception.BaseException;
import com.huifai.common.interceptor.PassToken;
import com.huifai.common.utils.MD5Util;
import com.huifai.common.utils.TokenUtil;
import com.huifai.entity.SysDataPermission;
import com.huifai.entity.SysPermission;
import com.huifai.entity.SysRole;
import com.huifai.entity.SysUser;
import com.huifai.service.*;
import com.huifai.vo.request.LoginUserInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * <br>==========================
 * <br> 创建人：吴传军
 * <br> 创建时间：2019/7/16 20:09
 * <br> 版本：1.0
 * <br> 描述：登录控制类
 * <br>==========================
 */
@RestController
@RequestMapping("/api/v1")
@Slf4j
public class TokenManageController extends BaseApp {

    private static final Logger logger = LoggerFactory.getLogger(TokenManageController.class);

    @Autowired
    private ISysUserService iSysUserService;
    @Autowired
    private ISysRoleService iSysRoleService;
    @Autowired
    private ISysPermissionService iSysPermissionService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private ISysDataPermissionService iSysDataPermissionService;
    @Autowired
    private ISysOrgService iSysOrgService;
    /**
     * 用户登录方法
     * @param userName
     * @param password
     * @return
     * @throws BaseException
     */
    @GetMapping(value = "/login")
    @PassToken
    public Map<String, Object> login(@RequestParam(value = "userName") String userName,
                                     @RequestParam(value = "password") String password, @RequestParam(required = false,value = "code") String code) throws Exception {
        List<String> paramList=new ArrayList<>();
        paramList.add(userName);
        paramList.add(password);
        ParameterValidator.validateStringParam(paramList);
        SysUser sysUser=new SysUser();
        sysUser.setUserName(userName);
        sysUser.setIsDeleted(SysConstant.IsDeleted.IS_DELETED_FALSE);
        List<SysUser> sysUserList=iSysUserService.findSysUsers(sysUser);
        if(sysUserList==null||sysUserList.size()==0){
            return  buildResponse(ERespCode.NO_CORRESPOND_DATA.code(),"用户名不存在",null);
        }
        Long userId =sysUserList.get(0).getId();
        sysUser.setPassword(MD5Util.MD5(password));
        sysUserList=iSysUserService.findSysUsers(sysUser);
        if(sysUserList==null||sysUserList.size()==0){
            int errorCount=0;
            //密码错误时记录次数，达到五次，账户锁定
            String errorCountStr =redisService.get(SysConstant.USER_LOCK+userName);
            if(StringUtils.isEmpty(errorCountStr)){
                errorCount=1;
            }else {
                errorCount= Integer.parseInt(errorCountStr)+1;
            }
            logger.info(userName+"密码错误次数_"+errorCountStr);
            redisService.set(SysConstant.USER_LOCK+userName, String.valueOf(errorCount));
            if(errorCount==5){
                //更新账号为锁定中
                SysUser sysUser1 = new SysUser();
                sysUser1.setId(userId);
                sysUser1.setStatus(0);
                iSysUserService.updateById(sysUser1);
            }
            if(errorCount>=5){
                return buildResponse(ERespCode.USER_LOCKED.code(),"账号已锁定，请联系管理员解锁",null);
            }
            return  buildResponse(ERespCode.NO_CORRESPOND_DATA.code(),"登录密码错误",null);
        }
        if(sysUserList.get(0).getStatus()==0){
            return buildResponse(ERespCode.USER_LOCKED.code(),"账号已锁定，请联系管理员解锁",null);
        }else {
            //清除错误次数
            redisService.del(SysConstant.USER_LOCK+userName);
        }
        sysUser=sysUserList.get(0);
        LoginUserInfo loginUserInfo = new LoginUserInfo();
        Map<String, Object> resultMap = new HashMap<>();
        //生成token并存入缓存中
        String token = TokenUtil.makeToken();
        redisService.set(token, String.valueOf(sysUser.getId()),60*60*12);
        resultMap.put("AccessToken",token);
        resultMap.put("sysUser",sysUser);
        List<SysRole> sysRoleList=iSysRoleService.findRolesByUserId(sysUser.getId());
        resultMap.put("roleList",sysRoleList);
        List<Long> roleIds=new ArrayList<>();
        if(sysRoleList!=null && sysRoleList.size()>0){
            for (SysRole sysRole : sysRoleList) {
                logger.info("非admin用户查询权限列表"+sysRole.getId());
                roleIds.add(sysRole.getId());
            }
        }
        List<Map<String, Object>> permissionResult=new ArrayList<>();
        List<SysPermission> firstMenuList = new ArrayList<>();
        List<SysPermission> childMenuList = new ArrayList<>();
        List<SysPermission> permissionList = new ArrayList<>();
         if(null == code){
             if("admin".equals(userName)){
                 permissionList = iSysPermissionService.list();
             }else {
                 logger.info("非admin用户查询权限=====");
                 permissionList=iSysPermissionService.findSysPermissionsByRoles(roleIds);
             }
         }else {
             if ("admin".equals(userName)) {
                 permissionList = iSysPermissionService.findSysPermissionsByAll(code);
             } else {
                 logger.info("非admin用户查询权限=====");
                 logger.info("普通用户的角色ID" + roleIds);
                 permissionList = iSysPermissionService.findSysPermissions(roleIds, code);
             }
         }
        if(permissionList!=null && permissionList.size()>0){
            for (SysPermission sysPermission : permissionList) {
                if(sysPermission.getParentId()==0){
                    firstMenuList.add(sysPermission);
                }else {
                    childMenuList.add(sysPermission);
                }
            }
            for (SysPermission menu : firstMenuList) {
                Map<String, Object> menuMap = new LinkedHashMap<>();
                menuMap.put("id",menu.getId());
                menuMap.put("path",menu.getPermissionPath());
                menuMap.put("pid",menu.getParentId());
                menuMap.put("type",menu.getPermissionType());
                Map<String, Object> metaMap = new LinkedHashMap<>();
                metaMap.put("title",menu.getPermissionName());
                if(StringUtils.isNotEmpty(menu.getIcon())){
                    metaMap.put("icon",menu.getIcon());
                }
                menuMap.put("meta",metaMap);
                menuMap.put("children",getMenuTree(childMenuList,menu.getId()));
                permissionResult.add(menuMap);
            }
        }
        resultMap.put("permissionList",permissionResult);

        //角色授予的组织机构权限
        List<Long> orgIdList = new ArrayList<>();
        if(SysConstant.DataPermissionType.ROLE.equals(sysUser.getPermissionType())){
            if(roleIds != null && roleIds.size()>0){
                List<SysDataPermission> dataPermissionList = iSysDataPermissionService.findSysDataPermissionsByRoles(roleIds);
                for (SysDataPermission sysDataPermission : dataPermissionList) {
                    orgIdList.add(sysDataPermission.getOrgId());
                }
            }
        }
        //用户登录信息存入到缓存中
        BeanUtils.copyProperties(sysUser,loginUserInfo);
        loginUserInfo.setSysRoleList(sysRoleList);
        loginUserInfo.setPermissionList(permissionResult);
        loginUserInfo.setOrgIdList(orgIdList);
        redisService.set(SysConstant.USER_PREFIX+sysUser.getId(), JSONObject.toJSONString(loginUserInfo),60*60*12);
        logger.info("登录成功====="+userName);
        return buildResponse(resultMap);
    }
    /**
     * 递归取出所有关系树
     * @param list
     * @param pid
     * @return
     */
    private List<Map<String, Object>> getMenuTree(List<SysPermission> list, Long pid) {
        List<Map<String, Object>> menuList=new ArrayList<>();
        //取出所有菜单
        for (int i = 0;i< list.size();i++) {
            SysPermission menu = list.get(i);
            if (menu.getParentId() == pid ) {
                Map<String, Object> menuMap = new LinkedHashMap<>();
                menuMap.put("id",menu.getId());
                menuMap.put("path",menu.getPermissionPath());
                menuMap.put("pid",menu.getParentId());
                menuMap.put("type",menu.getPermissionType());
                Map<String, Object> metaMap = new LinkedHashMap<>();
                metaMap.put("title",menu.getPermissionName());
                if(StringUtils.isNotEmpty(menu.getIcon())){
                    metaMap.put("icon",menu.getIcon());
                }
                menuMap.put("meta",metaMap);
                menuMap.put("children",getMenuTree(list,menu.getId()));
                menuList.add(menuMap);
            }
        }
        return menuList;
    }

    /**
     * 退出登录
     * @return
     * @throws BaseException
     */
    @GetMapping(value = "/loginOut")
    public Object loginOut(HttpServletRequest request) throws Exception {
        String token = request.getHeader("AccessToken");
        String userId=redisService.get(token);
        redisService.del(SysConstant.USER_PREFIX+userId);
        redisService.del(token);
        return buildResponse();
    }


    /**
     * token校验接口
     * @param request
     * @return
     * @throws BaseException
     */
    @GetMapping("/accessTokenCheck")
    @PassToken
    public Object tokenCheck(HttpServletRequest request) throws Exception {
        String token = request.getHeader("AccessToken");
        if(StringUtils.isEmpty(token)){
            return buildResponse(ERespCode.TOKEN_NULL,null);
        }
        String userId=redisService.get(token);
        if(StringUtils.isEmpty(userId)){
            return buildResponse(ERespCode.TOKEN_ERROR,null);
        }
        //校验成功刷新token和用户信息的缓存时间
        redisService.expire(token,1800);
        redisService.expire(SysConstant.USER_PREFIX+userId,1800);
        logger.info("校验成功=====token==="+token);
        return buildResponse();
    }

    /**
     * 根据token获取缓存中的用户信息
     * @param request
     * @return
     * @throws BaseException
     */
    @GetMapping(value = "/userInfo",produces="application/json;charset=UTF-8" )
    public String getUserInfo(HttpServletRequest request) throws Exception {
        String token = request.getHeader("AccessToken");
        String userId=redisService.get(token);
        logger.info("获取的用户userId=="+userId);
        logger.info("获取的用户信息====="+redisService.get(SysConstant.USER_PREFIX+userId));
        return redisService.get(SysConstant.USER_PREFIX+userId);
    }

    /**
     * 免密登录
     * @return
     */
    @GetMapping(value = "/login/noPassword")
    @PassToken
    public Map<String, Object> noPasswordLogin(@RequestParam(value = "userCode") String userCode) throws Exception {
        if(StringUtils.isEmpty(userCode)){
            throw new BadRequestException(ERespCode.MISSING_PARAMETER);
        }
        SysUser sysUser=new SysUser();
        sysUser.setUserCode(userCode);
        sysUser.setIsDeleted(SysConstant.IsDeleted.IS_DELETED_FALSE);
        List<SysUser> sysUserList=iSysUserService.findSysUsers(sysUser);
        if(sysUserList==null||sysUserList.size()==0){
            return  buildResponse(ERespCode.NO_CORRESPOND_DATA.code(),"用户编码不存在",null);
        }
        sysUser=sysUserList.get(0);
        LoginUserInfo loginUserInfo = new LoginUserInfo();
        //生成token并存入缓存中
        String token = TokenUtil.makeToken();
        redisService.set(token, String.valueOf(sysUser.getId()),60*60*12*15);
        BeanUtils.copyProperties(sysUser,loginUserInfo);
        redisService.set(SysConstant.USER_PREFIX+sysUser.getId(), JSONObject.toJSONString(loginUserInfo),60*60*12);
        return buildResponse(token);
    }
}
